package com.wsc.it.utils;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.util.TextUtils;

/**
 * 日期工具类
 *
 * @author jm
 */
public class DateUtils {
	
	// 以T分隔日期和时间，并带时区信息，符合ISO8601规范
	public static final String PATTERN_ISO = "yyyy-MM-dd'T'HH:mm:ss.SSSZZ";
	public static final String PATTERN_ISO_ON_SECOND = "yyyy-MM-dd'T'HH:mm:ssZZ";
	public static final String PATTERN_ISO_ON_DATE = "yyyy-MM-dd";
	public static final String PATTERN_ISO_ON_TIME = "HH:mm";
	//格式化年月日 年月日 时分
	public static final String PATTERN_ISO_ON_MINUTE = "yyyy-MM-dd HH:mm";

	// 以空格分隔日期和时间，不带时区信息
	public static final String PATTERN_DEFAULT = "yyyy-MM-dd HH:mm:ss.SSS";
	public static final String PATTERN_DEFAULT_ON_SECOND = "yyyy-MM-dd HH:mm:ss";
	public static final String PATTER_yyyyMMddHHmmss = "yyyyMMddHHmmss";



    /**
     * 根据开始日期,结束日期算出环比前的开始日期
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 环比前的日期
     */
    public static LocalDate getLastDate(LocalDate startDate, LocalDate endDate) {
        Long day = (endDate.toEpochDay() - startDate.toEpochDay());
        if (day <= 0) {
            throw new RuntimeException("选择的日期范围错误!");
        }
        return startDate.minusDays(day);
    }

    /**
     * 获取本月的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeginDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        return getDayStartTime(calendar.getTime());
    }

    /**
     * 获取本月的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getEndDayOfMonth() {
        Calendar calendar = Calendar.getInstance();
        calendar.set(getNowYear(), getNowMonth() - 1, 1);
        int day = calendar.getActualMaximum(5);
        calendar.set(getNowYear(), getNowMonth() - 1, day);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取上个月的第一天
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeforeFirstMonthdate() {
        SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar=Calendar.getInstance();
        calendar.add(Calendar.MONTH, -1);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获获取上个月的最后一天
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Date getBeforeLastMonthdate() {
        SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar=Calendar.getInstance();
        int month=calendar.get(Calendar.MONTH);
        calendar.set(Calendar.MONTH, month-1);
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        return getDayEndTime(calendar.getTime());
    }

    /**
     * 获取今年是哪一年
     */
    public static Integer getNowYear() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return Integer.valueOf(gc.get(1));
    }

    /**
     * 获取本月是哪一月
     */
    public static int getNowMonth() {
        Date date = new Date();
        GregorianCalendar gc = (GregorianCalendar) Calendar.getInstance();
        gc.setTime(date);
        return gc.get(2) + 1;
    }

    /**
     * 获取某个日期的开始时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getDayStartTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        if (null != date) {
            calendar.setTime(date);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar
                .get(Calendar.DAY_OF_MONTH), 0, 0, 0);
        calendar.set(Calendar.MILLISECOND, 0);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 获取某个日期的结束时间
     *
     * @return yyyy-MM-dd HH:mm:ss  格式
     */
    public static Timestamp getDayEndTime(Date date) {
        Calendar calendar = Calendar.getInstance();
        if (null != date) {
            calendar.setTime(date);
        }
        calendar.set(calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar
                .get(Calendar.DAY_OF_MONTH), 23, 59, 59);
        calendar.set(Calendar.MILLISECOND, 999);
        return new Timestamp(calendar.getTimeInMillis());
    }

    /**
     * 将 Date 转换成LocalDateTime
     * atZone()方法返回在指定时区从此Instant生成的ZonedDateTime。
     *
     * @param date
     * @return
     */
    public static LocalDateTime dateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDateTime();
    }

    /**
     * 微信时间戳转换为日期,注意微信时间戳为秒
     */
    public static LocalDateTime timestampToTime(Long timestamp) {
        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(timestamp, 0, ZoneOffset.ofHours(8));
        return localDateTime;
    }

    /**
     * Java将Unix时间戳转换成指定格式日期
     *
     * @param timestampString 时间戳 如："1473048265";
     * @param pattern         要格式化的格式 默认："yyyy-MM-dd HH:mm:ss";
     * @return 返回结果 如："2016-09-05 16:06:42";
     */
    public static Date timeStampToDate(String timestampString, String pattern) {
        if (TextUtils.isEmpty(pattern)) {
            pattern = "yyyy-MM-dd HH:mm:ss";
        }
        Long timestamp = Long.parseLong(timestampString) * 1000;
        String strDate = new SimpleDateFormat(pattern, Locale.CHINA).format(new Date(timestamp));
        return convertStringToDate(pattern, strDate);
    }

    /**
     * 将时间格式的字符串转为Date类型的标准日期
     *
     * @param pattern 时间格式
     * @param strDate 时间字符串
     * @return 解析日期
     */
    public static Date convertStringToDate(String pattern, String strDate) {
        if (StringUtils.isBlank(strDate)) {
            throw new RuntimeException("时间不能为空");
        }
        if (StringUtils.isBlank(pattern)) {
            throw new RuntimeException("时间格式不能为空");
        }
        Date date;
        SimpleDateFormat df = new SimpleDateFormat(pattern);
        try {
            date = df.parse(strDate);
        } catch (ParseException pe) {
            throw new RuntimeException(pe);
        }
        return (date);
    }

    /**
     * 将长时间格式时间转换为字符串 yyyy-MM-dd HH:mm:ss
     *
     * @param dateDate
     * @return
     */
    public static String dateToStr(java.util.Date dateDate, String pattern) {
        SimpleDateFormat formatter = new SimpleDateFormat(pattern);
        String dateString = formatter.format(dateDate);
        return dateString;
    }

    /**
     * @Author huhui
     * @Date 2019/8/21 13:59
     * @Description 获取指定起始时间内的每一天
     * @Param [startTime, endTime, pattern]
     * @Return java.util.List<java.util.Date>
     */
    public static List<Date> findDates(Date startTime, Date endTime, int amount) {
        List<Date> dateList = new ArrayList();
        Calendar cal = Calendar.getInstance();
        cal.setTime(startTime);
        dateList.add(startTime);

        while (cal.getTime().compareTo(endTime) < 0) {
            cal.add(Calendar.DAY_OF_MONTH, amount);
            if (cal.getTime().compareTo(endTime) < 0) {
                dateList.add(cal.getTime());
            }
        }
        dateList.add(endTime);
        return dateList;
    }

    /**
     * @Author huhui
     * @Date 2019/8/21 14:43
     * @Description 获取指定时间内的日期间隔
     * @Param [startTime, endTime, pattern, amount]
     * @Return java.util.List<java.lang.String>
     */
    public static List<Date> findHours(Date startTime, Date endTime, int amount) {
        List<Date> dateList = new ArrayList();
        Calendar cal = Calendar.getInstance();
        cal.setTime(startTime);

        dateList.add(startTime);

        while (cal.getTime().compareTo(endTime) < 0) {
            cal.add(Calendar.HOUR_OF_DAY, amount);
            dateList.add(cal.getTime());
        }
        return dateList;
    }

    /**
     * @Author huhui
     * @Date 2019/8/21 14:21
     * @Description 两个日期是否是同一天
     * @Param [date1, date2]
     * @Return boolean
     */
    public static boolean isSameDay(Date date1, Date date2) {
        if (date1 != null && date2 != null) {
            Calendar cal1 = Calendar.getInstance();
            cal1.setTime(date1);
            Calendar cal2 = Calendar.getInstance();
            cal2.setTime(date2);
            return isSameDay(cal1, cal2);
        } else {
            throw new IllegalArgumentException("The date must not be null");
        }
    }

    public static boolean isSameDay(Calendar cal1, Calendar cal2) {
        if (cal1 != null && cal2 != null) {
            return cal1.get(0) == cal2.get(0) && cal1.get(1) == cal2.get(1) && cal1.get(6) == cal2.get(6);
        } else {
            throw new IllegalArgumentException("The date must not be null");
        }
    }

    /**
     * 判断当前时间是否在[startTime, endTime]区间，注意时间格式要一致
     *
     * @param nowTime   当前时间
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static boolean isEffectiveDate(Date nowTime, Date startTime, Date endTime) {
        if (nowTime.getTime() == startTime.getTime()
                || nowTime.getTime() == endTime.getTime()) {
            return true;
        }
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);
        Calendar begin = Calendar.getInstance();
        begin.setTime(startTime);
        Calendar end = Calendar.getInstance();
        end.setTime(endTime);
        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 返回某个日期后几天的日期
     */
    public static Date getFrontDay(Date date, int num) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.DATE, cal.get(Calendar.DATE) + num);
        return cal.getTime();
    }

    /**
     * 返回某个日期后几个月的日期
     */
    public static Date getFrontMonth(Date date, int num) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) + num);
        return cal.getTime();
    }

    /**
     * 返回某个日期后几个月的日期
     */
    public static Date getFrontYear(Date date, int num) {
        Calendar cal = new GregorianCalendar();
        cal.setTime(date);
        cal.set(Calendar.YEAR, cal.get(Calendar.YEAR) + num);
        return cal.getTime();
    }

    /**
     *  判断【时段区间】是否重叠
     *
     * @param lsitMap		区间集合
     * 									date 		与这个区间绑定的ID信息或描述信息（用于执行成功后后续操作的标识符）
     * 									startArea 	区间开始值
     * 									endArea 	区间结束值
     * [
     * 		{date=AS08998AS0DF8A0S9DF8, startArea=10800000, endArea=21600000},
     * 		{date=AS08998AS0DF8A0S9DF9, startArea=21600000, endArea=28800000},
     * 		{date=AS08998AS0DF8A0S9DG0, startArea=25200000, endArea=32400000}
     * ]
     *
     * @param doFristStop	中断操作
     * 									true 		只要有重叠，立即返回
     * 									false 		直到所有值遍历完才返回
     * @return
     * @throws Exception
     */
    public static List<Map<String, String>> checkTimeArea(List<Map<String, String>> lsitMap, boolean doFristStop) throws Exception {
        SimpleDateFormat SDF_HH_MM_SS = new SimpleDateFormat("HH:mm:ss");
        Collections.sort(lsitMap, new Comparator<Map<String, String>>() {
            @Override
            public int compare(Map<String, String> o1, Map<String, String> o2) {
                Long num_1 = Long.valueOf(o1.get("startArea"));
                Long num_2 = Long.valueOf(o2.get("startArea"));
                int result = num_1.compareTo(num_2);
                return result;
            }
        });
        List<Map<String, String>> retList = new ArrayList<Map<String, String>>();
        Map<String, String> retMap = null;
        for (int i = 0; i < lsitMap.size(); i++) {
            BigDecimal startInt = new BigDecimal(lsitMap.get(i).get("startArea"));
            BigDecimal endInt = new BigDecimal(lsitMap.get(i).get("endArea"));
            for (int j = i + 1; j < lsitMap.size(); j++) {
                BigDecimal toStartInt = new BigDecimal(lsitMap.get(j).get("startArea"));
                BigDecimal toEndInt = new BigDecimal(lsitMap.get(j).get("endArea"));
                /**
                 * 如果指定的数与参数相等返回0。
                 * 如果指定的数小于参数返回 -1。
                 * 如果指定的数大于参数返回 1。
                 *
                 * 案例：
                 * Integer x = 5;
                 *
                 * 输出结果：
                 * 1
                 * 0
                 * -1
                 */
                if (toStartInt.compareTo(endInt) == -1 || (startInt.compareTo(toStartInt) == 0 && endInt.compareTo(toEndInt) == 0)) {
                    retMap = new HashMap<String, String>();
                    retMap.put("old", lsitMap.get(i).get("date"));
                    retMap.put("oldArea", SDF_HH_MM_SS.format(new Date(Long.valueOf(lsitMap.get(i).get("startArea")))) + "-" + SDF_HH_MM_SS.format(new Date(Long.valueOf(lsitMap.get(i).get("endArea")))));
                    retMap.put("new", lsitMap.get(j).get("date"));
                    retMap.put("newArea", SDF_HH_MM_SS.format(new Date(Long.valueOf(lsitMap.get(j).get("startArea")))) + "-" + SDF_HH_MM_SS.format(new Date(Long.valueOf(lsitMap.get(j).get("endArea")))));
                    retList.add(retMap);
                    if (doFristStop) {
                        return retList;
                    }
                }
            }
        }
        return retList;
    }
    //获取秒级的时间戳（微信支付使用）
    public static long getTimeStamp() {
	    Date d = new Date();
	    long timeStamp = d.getTime() / 1000;     //getTime()得到的是微秒， 需要换算成秒
	    return timeStamp;
	}

}
